﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using HelixToolkit.Wpf;
using PDBSmartMVVM.model;
using PDBSmartMVVM.viewmodel;

namespace PDBSmartMVVM
{
    public enum AtomType
    {
        N = 1,
        ND1,
        ND2,
        NE,
        NE1,
        NE2,
        NZ,
        NH1,
        NH2,
        C,
        CA,
        CB,
        CG,
        CG1,
        CG2,
        CD,
        CD1,
        CD2,
        CE,
        CE1,
        CE2,
        CE3,
        CZ,
        CZ2,
        CZ3,
        CH2,
        O,
        OG,
        OG1,
        OD1,
        OD2,
        OE1,
        OE2,
        OH,
        OXT,
        SD,
        SG
    }

    public enum NType
    {
        N = 1,
        ND1,
        ND2,
        NE,
        NE1,
        NE2,
        NZ,
        NH1,
        NH2,
    }

    public enum CType
    {
        C = 1,
        CA,
        CB,
        CG,
        CG1,
        CG2,
        CD,
        CD1,
        CD2,
        CE,
        CE1,
        CE2,
        CE3,
        CZ,
        CZ2
    }

    public enum OType
    {
        O = 1,
        OG,
        OG1,
        OD1,
        OD2,
        OE1,
        OE2,
        OH,
        OXT,
    }

    public enum AminoType
    {
        CYS = 1,
        THR,
        ARG,
        PRO,
        ASN,
        LYS,
        SER,
        LEU,
        ILE,
        HIS,
        GLY,
        ALA,
        PHE,
        TYR,
        GLN,
        GLU,
        ASP,
        VAL,
        MET,
        TRP,
    }

    public static class Utils
    {
        public static Material SelectedMaterial = new EmissiveMaterial(new SolidColorBrush(Color.FromRgb(0, 255, 120)));

        public static Material GetColorByAtomType(AtomType atomType)
        {
            if (atomType.ToString().StartsWith("N"))
                return new EmissiveMaterial(new SolidColorBrush(Color.FromRgb(0, 0, 255)));
            if (atomType.ToString().StartsWith("C"))
                return new EmissiveMaterial(new SolidColorBrush(Color.FromRgb(180, 180, 180)));
            if (atomType.ToString().StartsWith("S"))
                return new EmissiveMaterial(new SolidColorBrush(Color.FromRgb(255, 242, 0)));
            if (atomType.ToString().StartsWith("O"))
                return new EmissiveMaterial(new SolidColorBrush(Color.FromRgb(255, 0, 0)));
            return Materials.Gray;
        }

        public static List<LinesVisual3D> DrawAnino(Amino amino)
        {
            var result = new List<LinesVisual3D>();
            LinesVisual3D line;
            Atom N, ND1, ND2, NE, NE1, NE2, NZ, NH1, NH2, C, CA, CB, CG, CG1, CG2, CD, CD1, CD2, CE, CE1, CE2, CE3, CZ, CZ2, O, OG, OG1, OD1, OD2, OE1, OE2, OH, OXT, SD, SG;
            N = (Atom)amino.Atoms[AtomType.N];
            CA = (Atom) amino.Atoms[AtomType.CA];
            C = (Atom)amino.Atoms[AtomType.C];
            O = (Atom)amino.Atoms[AtomType.O];
            line = new LinesVisual3D { Color = Colors.White };
            line.Points.Add(N.Point);
            line.Points.Add(CA.Point);
            result.Add(line);
            line = new LinesVisual3D { Color = Colors.White };
            line.Points.Add(CA.Point);
            line.Points.Add(C.Point);
            result.Add(line);
            if (O != null)
            {
                line = new LinesVisual3D { Color = Colors.White };
                line.Points.Add(C.Point);
                line.Points.Add(O.Point);
                result.Add(line); 
            }

            switch (amino.AminoType)
            {
                case AminoType.MET:
                    #region
                    CB = (Atom)amino.Atoms[AtomType.CB];
                    CG = (Atom)amino.Atoms[AtomType.CG];
                    SD =  (Atom)amino.Atoms[AtomType.SD];
                    CE =  (Atom)amino.Atoms[AtomType.CE];

                    if (CB == null || CG == null || SD == null || CE == null)
                        return result;
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CG.Point);
                    line.Points.Add(SD.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(SD.Point);
                    line.Points.Add(CE.Point);
                    result.Add(line);


                    #endregion
                    break;

                case AminoType.ASN:
                    #region
                    CB = (Atom)amino.Atoms[AtomType.CB];
                    CG = (Atom)amino.Atoms[AtomType.CG];
                    OD1 =  (Atom)amino.Atoms[AtomType.OD1];
                    ND2 =  (Atom)amino.Atoms[AtomType.ND2];
                    if (CB == null || CG == null || OD1 == null || ND2 == null)
                        return result;

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CG.Point);
                    line.Points.Add(OD1.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CG.Point);
                    line.Points.Add(ND2.Point);
                    result.Add(line);

                    #endregion
                    break;

                case AminoType.VAL:
                    #region
                    CB = (Atom)amino.Atoms[AtomType.CB];
                    CG1 =  (Atom)amino.Atoms[AtomType.CG1];
                    CG2 =  (Atom)amino.Atoms[AtomType.CG2];
                    if (CB == null || CG1 == null || CG2 == null)
                        return result;
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);
                    //me.AddCylinder(CB.Point, CG1.Point);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG1.Point);
                    result.Add(line);

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG2.Point);
                    result.Add(line);


                    #endregion
                    break;

                case AminoType.THR:
                    #region
                    CB = (Atom)amino.Atoms[AtomType.CB];
                    OG1 =  (Atom)amino.Atoms[AtomType.OG1];
                    CG2 =  (Atom)amino.Atoms[AtomType.CG2];
                    if (CB == null || OG1 == null || CG2 == null)
                        return result;
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(OG1.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG2.Point);
                    result.Add(line);


                    #endregion
                    break;

                case AminoType.CYS:
                    #region
                    CB = (Atom)amino.Atoms[AtomType.CB];
                    SG =  (Atom)amino.Atoms[AtomType.SG];
                    if (CB == null || SG == null)
                        return result;


                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(SG.Point);
                    result.Add(line);


                    #endregion
                    break;

                case AminoType.ARG:
                    #region
                    CB = (Atom)amino.Atoms[AtomType.CB];
                    CG = (Atom)amino.Atoms[AtomType.CG];
                    CD =  (Atom)amino.Atoms[AtomType.CD];

                    NE =  (Atom)amino.Atoms[AtomType.NE];
                    CZ =  (Atom)amino.Atoms[AtomType.CZ];
                    NH1 =  (Atom)amino.Atoms[AtomType.NH1];
                    NH2 =  (Atom)amino.Atoms[AtomType.NH2];

                    if (CB == null || CG == null || CD == null || NE == null
                        || CZ == null || NH1 == null || NH2 == null)
                        return result;

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CD.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD.Point);
                    line.Points.Add(NE.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(NE.Point);
                    line.Points.Add(CZ.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(NH2.Point);
                    line.Points.Add(CZ.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(NH1.Point);
                    line.Points.Add(CZ.Point);
                    result.Add(line);


                    #endregion
                    break;

                case AminoType.PRO:
                    #region
                    CB = (Atom)amino.Atoms[AtomType.CB];
                    CG = (Atom)amino.Atoms[AtomType.CG];
                    CD =  (Atom)amino.Atoms[AtomType.CD];

                    if (CB == null || CG == null || CD == null)
                        return result;


                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CD.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD.Point);
                    line.Points.Add(N.Point);
                    result.Add(line);


                    #endregion
                    break;
                case AminoType.LYS:
                    #region
                    CB = (Atom)amino.Atoms[AtomType.CB];
                    CG = (Atom)amino.Atoms[AtomType.CG];
                    CD =  (Atom)amino.Atoms[AtomType.CD];
                    CE =  (Atom)amino.Atoms[AtomType.CE];
                    NZ =  (Atom)amino.Atoms[AtomType.NZ];
                    if (CB == null || CG == null || CD == null || CE == null || NZ == null)
                        return result;


                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CD.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD.Point);
                    line.Points.Add(CE.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(NZ.Point);
                    line.Points.Add(CE.Point);
                    result.Add(line);


                    #endregion
                    break;

                case AminoType.SER:
                    #region

                    CB = (Atom)amino.Atoms[AtomType.CB];
                    OG =  (Atom)amino.Atoms[AtomType.OG];
                    if (CB == null || OG == null)
                        return result;


                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(OG.Point);
                    result.Add(line);


                    #endregion
                    break;

                case AminoType.LEU:
                    #region
                    CB = (Atom)amino.Atoms[AtomType.CB];
                    CG = (Atom)amino.Atoms[AtomType.CG];
                    CD1 =  (Atom)amino.Atoms[AtomType.CD1];
                    CD2 =  (Atom)amino.Atoms[AtomType.CD2];
                    if (CB == null || CG == null || CD1 == null || CD2 == null)
                        return result;



                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CG.Point);
                    line.Points.Add(CD1.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CG.Point);
                    line.Points.Add(CD2.Point);
                    result.Add(line);


                    #endregion
                    break;

                case AminoType.ILE:
                    #region
                    CB = (Atom)amino.Atoms[AtomType.CB];
                    CG1 =  (Atom)amino.Atoms[AtomType.CG1];
                    CG2 =  (Atom)amino.Atoms[AtomType.CG2];
                    CD1 =  (Atom)amino.Atoms[AtomType.CD1];
                    if (CB == null || CG1 == null || CG2 == null || CD1 == null)
                        return result;

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);


                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG1.Point);
                    result.Add(line);

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG2.Point);
                    result.Add(line);

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CG1.Point);
                    line.Points.Add(CD1.Point);
                    result.Add(line);


                    #endregion
                    break;

                case AminoType.HIS:
                    #region
                    CB = (Atom)amino.Atoms[AtomType.CB];
                    CG = (Atom)amino.Atoms[AtomType.CG];
                    ND1 =  (Atom)amino.Atoms[AtomType.ND1];
                    CD2 =  (Atom)amino.Atoms[AtomType.CD2];
                    CE1 =  (Atom)amino.Atoms[AtomType.CE1];
                    NE2 =  (Atom)amino.Atoms[AtomType.NE2];
                    if (CB == null || CG == null || ND1 == null || CD2 == null
                        || CE1 == null || NE2 == null)
                        return result;


                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CG.Point);
                    line.Points.Add(ND1.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CE1.Point);
                    line.Points.Add(ND1.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CE1.Point);
                    line.Points.Add(NE2.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD2.Point);
                    line.Points.Add(NE2.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD2.Point);
                    line.Points.Add(CG.Point);
                    result.Add(line);


                    #endregion
                    break;

                case AminoType.GLY:
                    #region


                    OXT =  (Atom)amino.Atoms[AtomType.OXT];
                    if (OXT == null)
                        break;
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(C.Point);
                    line.Points.Add(OXT.Point);
                    result.Add(line);

                    #endregion
                    break;

                case AminoType.ALA:
                    #region
                    CB = (Atom)amino.Atoms[AtomType.CB];

                    if (CB == null)
                        return result;

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);


                    #endregion
                    break;

                case AminoType.PHE:
                    #region
                    CB = (Atom)amino.Atoms[AtomType.CB];
                    CG = (Atom)amino.Atoms[AtomType.CG];
                    CD1 =  (Atom)amino.Atoms[AtomType.CD1];
                    CD2 =  (Atom)amino.Atoms[AtomType.CD2];
                    CE1 =  (Atom)amino.Atoms[AtomType.CE1];
                    CE2 =  (Atom)amino.Atoms[AtomType.CE2];
                    CZ =  (Atom)amino.Atoms[AtomType.CZ];
                    if (CB == null || CG == null || CD1 == null || CD2 == null ||
                        CE1 == null || CE2 == null || CZ == null)
                        return result;


                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CG.Point);
                    line.Points.Add(CD1.Point);
                    result.Add(line);

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD1.Point);
                    line.Points.Add(CE1.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CZ.Point);
                    line.Points.Add(CE1.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CZ.Point);
                    line.Points.Add(CE2.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD2.Point);
                    line.Points.Add(CE2.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD2.Point);
                    line.Points.Add(CG.Point);
                    result.Add(line);


                    #endregion
                    break;

                case AminoType.TYR:
                    #region
                    CB = (Atom)amino.Atoms[AtomType.CB];
                    CG = (Atom)amino.Atoms[AtomType.CG];
                    CD1 =  (Atom)amino.Atoms[AtomType.CD1];
                    CD2 =  (Atom)amino.Atoms[AtomType.CD2];
                    CE1 =  (Atom)amino.Atoms[AtomType.CE1];
                    CE2 =  (Atom)amino.Atoms[AtomType.CE2];
                    CZ =  (Atom)amino.Atoms[AtomType.CZ];
                    OH =  (Atom)amino.Atoms[AtomType.OH];
                    if (CB == null || CG == null || CD1 == null || CD2 == null
                        || CE1 == null || CE2 == null || CZ == null || OH == null)
                        return result;

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CG.Point);
                    line.Points.Add(CD1.Point);
                    result.Add(line);

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD1.Point);
                    line.Points.Add(CE1.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CZ.Point);
                    line.Points.Add(CE1.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CZ.Point);
                    line.Points.Add(CE2.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD2.Point);
                    line.Points.Add(CE2.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD2.Point);
                    line.Points.Add(CG.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CZ.Point);
                    line.Points.Add(OH.Point);
                    result.Add(line);


                    #endregion
                    break;

                case AminoType.GLN:
                    #region
                    // www.fli-leibniz.de 
                    CB = (Atom)amino.Atoms[AtomType.CB];
                    CG = (Atom)amino.Atoms[AtomType.CG];
                    CD =  (Atom)amino.Atoms[AtomType.CD];
                    NE2 =  (Atom)amino.Atoms[AtomType.NE2];
                    OE1 =  (Atom)amino.Atoms[AtomType.OE1];
                    OXT =  (Atom)amino.Atoms[AtomType.OXT];
                    if (CB == null || CG == null || CD == null || NE2 == null
                        || OE1 == null)
                        return result;

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CD.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD.Point);
                    line.Points.Add(OE1.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD.Point);
                    line.Points.Add(NE2.Point);
                    result.Add(line);
                    if (OXT == null)
                        break;
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(C.Point);
                    line.Points.Add(OXT.Point);
                    result.Add(line);
                    #endregion
                    break;

                case AminoType.GLU:
                    #region

                    CB = (Atom)amino.Atoms[AtomType.CB];
                    CG = (Atom)amino.Atoms[AtomType.CG];
                    CD =  (Atom)amino.Atoms[AtomType.CD];

                    OE1 =  (Atom)amino.Atoms[AtomType.OE1];
                    OE2 =  (Atom)amino.Atoms[AtomType.OE2];

                    if (CB == null || CG == null || CD == null || OE1 == null || OE2 == null)
                        return result;

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CD.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD.Point);
                    line.Points.Add(OE1.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD.Point);
                    line.Points.Add(OE2.Point);
                    result.Add(line);


                    #endregion
                    break;

                case AminoType.ASP:
                    #region

                    CB = (Atom)amino.Atoms[AtomType.CB];
                    CG = (Atom)amino.Atoms[AtomType.CG];

                    OD1 =  (Atom)amino.Atoms[AtomType.OD1];
                    OD2 =  (Atom)amino.Atoms[AtomType.OD2];
                    if (CB == null || CG == null || OD1 == null || OD2 == null)
                        return result;

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG.Point);
                    result.Add(line);

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CG.Point);
                    line.Points.Add(OD1.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CG.Point);
                    line.Points.Add(OD2.Point);
                    result.Add(line);


                    #endregion
                    break;

                case AminoType.TRP:
                    #region
                    CB = (Atom)amino.Atoms[AtomType.CB];
                    CG = (Atom)amino.Atoms[AtomType.CG];
                    CD1 =  (Atom)amino.Atoms[AtomType.CD1];
                    CD2 =  (Atom)amino.Atoms[AtomType.CD2];
                    CE2 =  (Atom)amino.Atoms[AtomType.CE2];
                    NE1 =  (Atom)amino.Atoms[AtomType.NE1];
                    CZ2 =  (Atom)amino.Atoms[AtomType.CZ2];
                    CE3 =  (Atom)amino.Atoms[AtomType.CE3];
                    var CZ3 =  (Atom)amino.Atoms[AtomType.CZ3];
                    var CH2 =  (Atom)amino.Atoms[AtomType.CH2];
                    if (CB == null || CG == null || CD1 == null || CD2 == null
                        || CE2 == null || NE1 == null || CZ2 == null || CE3 == null
                        || CZ3 == null || CH2 == null)
                        return result;
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CA.Point);
                    line.Points.Add(CB.Point);
                    result.Add(line);

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CB.Point);
                    line.Points.Add(CG.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CG.Point);
                    line.Points.Add(CD1.Point);
                    result.Add(line);

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD1.Point);
                    line.Points.Add(NE1.Point);
                    result.Add(line);

                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(NE1.Point);
                    line.Points.Add(CE2.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD2.Point);
                    line.Points.Add(CE2.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD2.Point);
                    line.Points.Add(CG.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CD2.Point);
                    line.Points.Add(CE3.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CE3.Point);
                    line.Points.Add(CZ3.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CZ3.Point);
                    line.Points.Add(CH2.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CH2.Point);
                    line.Points.Add(CZ2.Point);
                    result.Add(line);
                    line = new LinesVisual3D { Color = Colors.White };
                    line.Points.Add(CZ2.Point);
                    line.Points.Add(CE2.Point);
                    result.Add(line);


                    #endregion
                    break;

                default:
                    break;
            }
            return result;
        }

        public static double Tors(Point3D i, Point3D j, Point3D k, Point3D l)
        {
            double xij = i.X - j.X;
            double yij = i.Y - j.Y;
            double zij = i.Z - j.Z;
            double xkj = k.X - j.X;
            double ykj = k.Y - j.Y;
            double zkj = k.Z - j.Z;
            double xkl = k.X - l.X;
            double ykl = k.Y - l.Y;
            double zkl = k.Z - l.Z;
            double dxi = (yij * zkj) - (zij * ykj);
            double dyi = (zij * xkj) - (xij * zkj);
            double dzi = (xij * ykj) - (yij * xkj);
            double gxi = (zkj * ykl) - (ykj * zkl);
            double gyi = (xkj * zkl) - (zkj * xkl);
            double gzi = (ykj * xkl) - (xkj * ykl);

            double ct = dxi * gxi + dyi * gyi + dzi * gzi;

            double bi = Math.Sqrt(dxi * dxi + dyi * dyi + dzi * dzi);
            double bk = Math.Sqrt(gxi * gxi + gyi * gyi + gzi * gzi);

            double z1 = 1 / bi;
            double z2 = 1 / bk;
            ct = ct * z1 * z2;
            double ap = Math.Acos(ct);
            double s = xkj * (dzi * gyi - dyi * gzi) + ykj * (dxi * gzi - dzi * gxi) + zkj * (dyi * gxi - dxi * gyi);

            if (s < 0) ap = -1.0 * ap;
            ap = ap > 0 ? Math.PI - ap : -(Math.PI + ap);
            return ap;

        }

        /// <summary>
        /// arg(exp(i*x)/exp(i*y))где i - мнимая единица, arg - функция комплексного аргумента. Значения углов x и y задаются в радианах.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static double CircularDistance(double a, double b)
        {
            var a_real = Math.Cos(a);
            var a_imagine = Math.Sin(a);
            var b_real = Math.Cos(b);
            var b_imagine = Math.Sin(b);

            var division_real = a_real*b_real + a_imagine*b_imagine;
            var division_imagine = a_imagine*b_real - a_real*b_imagine;


            return Math.Atan2(division_imagine, division_real);
        }

        public static List<LinesVisual3D> DrawDifferences(List<Amino> aminos, List<Angles> angles)
        {
            if (angles.Count == 0)
                return new List<LinesVisual3D>();
            var result = new List<LinesVisual3D>();
            LinesVisual3D line;
            Atom N, CA, C;
            var colors = GetColors(angles);
            for (int i = 0; i < aminos.Count-1; i++)
            {
                N = (Atom)aminos[i].Atoms[AtomType.N];
                CA = (Atom)aminos[i].Atoms[AtomType.CA];
                C = (Atom)aminos[i].Atoms[AtomType.C];
               
                var phiColor = colors[aminos[i].Number][0];
                var psiColor = colors[aminos[i].Number][1];
                line = new LinesVisual3D { Color = phiColor };
                line.Points.Add(N.Point);
                line.Points.Add(CA.Point);
                result.Add(line);
                line = new LinesVisual3D { Color = psiColor };
                line.Points.Add(CA.Point);
                line.Points.Add(C.Point);
                result.Add(line);
            }

            
            return result;
        }

        public static Dictionary<int, List<Color>> GetColors(List<Angles> angles)

        {
            var result = new Dictionary<int, List<Color>>();
            var maxphi = angles.Where(s=>s.Phi.HasValue).Max(s => Math.Abs(s.Phi.Value));
            var minphi = angles.Where(s=>s.Phi.HasValue).Min(s => Math.Abs(s.Phi.Value));

            var maxpsi = angles.Where(s => s.Psi.HasValue).Max(s => Math.Abs(s.Psi.Value));
            var minpsi = angles.Where(s => s.Psi.HasValue).Min(s => Math.Abs(s.Psi.Value));

            var phiDelta = 255d/(Math.Abs(maxphi) - Math.Abs(minphi));
            var psiDelta = 255d/(Math.Abs(maxpsi) - Math.Abs(minpsi));

            foreach (var angle in angles)
            {
                double phiRedValue=0, psiRedValue=0; 
                if (angle.Phi.HasValue)
                {
                    phiRedValue = Math.Abs(angle.Phi.Value)*phiDelta;
                }
                if (angle.Psi.HasValue)
                {
                    psiRedValue = Math.Abs(angle.Psi.Value) * psiDelta;
                }
                var colors = new List<Color>
                    {
                        {Color.FromRgb((byte) phiRedValue, 0, 0)},
                        {Color.FromRgb((byte) psiRedValue, 0, 0)},
                    };
                result.Add(angle.AminoNumber, colors);
            }
            return result;
        }
    }
}
